//
//  ZWayPrivate.h
//  Part of Z-Way.C library
//
//  Created by Alex Skalozub on 6/24/12.
//  Based on Z-Way source code written by Christian Paetz and Poltorak Serguei
//
//  Copyright (c) 2012 Z-Wave.Me
//  All rights reserved
//  info@z-wave.me
//
//  This source file is subject to the terms and conditions of the
//  Z-Wave.Me Software License Agreement which restricts the manner
//  in which it may be used.
//

#ifndef zway_private_h
#define zway_private_h

#include "ZDefsPrivate.h"
#include "ZDefsPublic.h"
#include "ZByteOperations.h"
#include "ZDataPrivate.h"
#include "ZSerialIO.h"
#include "ZLog.h"
#include "ZJob.h"
#include "ZTimerPrivate.h"
#include "ZDDXOperationsPrivate.h"
#include "ZThreadPrivate.h"

#define DEVUUID_SIZE 16

struct _xmlDoc;

struct _ZWay 
{
    struct _ZDataRootObject data_root;
    _ZddxOperationsConfigCtx_t ctx_zddx;
    
    ZIoPortSettings_t port_name; // string containing port name
    speed_t speed;              // port speed in kbps
    int dt;                     // sleep time in ms between polls
#if ! defined(__ZWAY_STATIC_CONFIGURATION__)
    ZWSTR translations_dir; // string containing translations directory
#endif
#if __ZWAY_ZDDX_DB__
    ZWSTR zddx_dir;         // string containing zddx directory
#endif
    
    ZWHANDLE port_handle;        // handle for port object
    ZWTHREAD worker_thread; // handle of worker thread
    ZWMUTEX main_mutex;     // main sync mutex
    ZTerminationCallback termination_callback; // callback on working thread termination
    void* termination_callback_arg; // arg passed to termination callback
    
    volatile ZWBOOL is_terminating; // termination flag
    volatile ZWBOOL is_running;     // running flag
    volatile ZWBOOL is_valid;       // structure validity flag
    ZWBOOL serial_api_ininitalized; // flag if GetSerialAPICapabilities was finished
    
    ZWLog logger;

    ZQueueEntry queue_head;         // queue head
    ZQueueEntry queue_tail;         // queue tail (for fast inserts)
    ZWMUTEX queue_mutex;            // queue sync mutex
    ZWMUTEXATTR queue_mutex_attr;   // queue sync mutex attrs (for reentrancy)
    
    size_t max_resend_count:3;
    size_t max_request_resend_count:2;
    size_t vendor_value:16;
    size_t vendor_mask:3;
    
    float timeout_channel;
    float timeout_ack;
    float timeout_response;
    float timeout_callback_first;
    float timeout_callback_more;
    float timeout_reply;
    float timeout_done;
    
    ZWBYTE uuid[DEVUUID_SIZE];
    
    uint16_t vendor_id;
    
    ZWBYTE callback_id;
    
    // bitmask for supported function classes
    ZWBYTE supported_function_classes[32];
    
    ZDataHolder controller;
    
    ZDeviceList devices;
    
    ZDevice dummy_device;
    
    ZDeviceCallbackList device_callbacks;
    
    int ticks;
    
    ZWBOOL try_to_become_sis:1;
    ZWBOOL discovery_finished:1;
    ZWBOOL discovery_error:1;
    ZWBOOL long_range_devices_loaded:1;
    ZWBOOL is_request:1;
    ZWBOOL run_inclusion_timer:1;
    ZWBOOL check_inclusion_controller_cc_in_nif:1;
    
    // defines if nodes IDs are 8 or 16 bits
    ZWBOOL isLR:1;
    
    // flag to indicate controler has issues with packet sizes
    ZWBOOL buggy_stick:1;
    
#if !defined(__ZWAY_STATIC_CONFIGURATION__)
    struct
    {
        struct _xmlDoc *defaults;
        struct _xmlDoc *aec;
        struct _xmlDoc *alarms;
        struct _xmlDoc *device_classes;
        struct _xmlDoc *scales;
        struct _xmlDoc *sdk_ids;
        struct _xmlDoc *thermostat_modes;
        struct _xmlDoc *vendor_ids;
        struct _xmlDoc *lock_events;
        struct _xmlDoc *zwave_plus;
        struct _xmlDoc *color_capabilities;
        struct _xmlDoc *barrier_signals;
        struct _xmlDoc *indicators;
        struct _xmlDoc *user_code;
        struct _xmlDoc *door_lock;
    } xml;
#endif
    ZNonceList nonces;

    // S2 timer for controller inclusion as secondary
    _ZTimer_t *s2_delayed_controller_interview_timer;
    _ZTimer_t *s2_joining_abandon_timer;
    uint8_t secondary_unauth_key_flag;
    
    // Timers
    _ZTimerCtx_t *ctx_timers;
    
    // powerlevel timer in seconds
    float powerlevel_time_remaining;
    
    // last set powerlevel value
    ZWBYTE powerlevel_value;

    ZWBYTE *caps_nonce;

    // buffered requests received while discovery is still ongoing
    // it is critical for Security to handle them ASAP after discovery is finished
    ZBufferedCommand buffered_head;
    ZBufferedCommand buffered_tail;
    
    // count of devices in AG left to notify when controller is being reset
    ZWBYTE controller_reset_job_counter;

    ZWayConfiguration_t configuration;

    ZWBYTE receive_buffer[MAX_PACKET_SIZE];
    ZWBYTE send_buffer[MAX_PACKET_SIZE];
    ZWCHAR send_buffer_prefix[20];
};

static inline ZWLog _zway_get_logger(const ZWay zway)
{
    return _zdata_root_get_log(&zway->data_root);
}

// quick access to devices and instances
ZWEXPORT_PRIVATE ZDevice _zway_get_device(const ZWay zway, ZWNODE node_id);
ZWEXPORT_PRIVATE ZInstance _zway_get_instance(const ZWay zway, ZWNODE node_id, ZWBYTE instance_id);
ZWEXPORT_PRIVATE ZCommand _zway_get_command(const ZWay zway, ZWNODE node_id, ZWBYTE instance_id, ZWBYTE command_id);
ZWEXPORT_PRIVATE ZDevice _zway_get_controller_device(const ZWay zway);

// add a device if not exists, and optionally update type and NIF
// - if node_type == -1, node type is not updated
// - if nif_length == -1, NIF is not updated
ZDevice _zway_update_device(ZWay zway, ZWNODE node_id, int node_type, int nif_length, const ZWBYTE *nif, ZWBOOL manyDevices);
ZDevice _zway_update_device_ext(ZWay zway, ZWNODE node_id, int node_type, int nif_length, const ZWBYTE *nif, ZWBOOL manyDevices, ZWBOOL add_node_network);

// update routing table
ZWEXPORT_PRIVATE ZWError _zway_update_routes(ZWay zway);

ZWError zway_rediscover(ZWay zway);

ZWError _zway_controller_load_nif(ZWay zway);
ZWError _zway_controller_serial_api_application_node_information(ZWay zway);
ZWEXPORT_PRIVATE ZWError _zway_controller_assign_suc(ZWay zway, ZWNODE node_id);
ZWEXPORT_PRIVATE ZWError _zway_controller_enable_suc(ZWay zway);
ZWEXPORT_PRIVATE ZWError _zway_controller_enable_sis(ZWay zway);
ZWEXPORT_PRIVATE ZWError _zway_controller_disable_suc(ZWay zway);

ZWBYTE _zway_fill_nif_buffer(const ZWay zway, ZWSTR nif, ZWBOOL secure, ZWBYTE *buffer, ZWBYTE maxLength);

void _zway_device_callback(const ZWay zway, ZWDeviceChangeType type, ZWNODE node_id, ZWBYTE instance_id, ZWBYTE command_id);

ZWBOOL _zway_is_hw_7gen(ZWay zway);
ZWBOOL _zway_is_zme_hardware(ZWay zway);
ZWBOOL _zway_is_trident_hardware(ZWay zway);

static inline ZWBYTE _zway_get_node_size(const ZWay zway)
{
    return zway->isLR ? 2 : 1;
};

static inline ZWNODE _zway_ptr_to_node_ext(const ZWBYTE *const ptr, const ZWBYTE size)
{
    return (ZWNODE)_bytes_to_int(ptr, size);
};

static inline ZWNODE _zway_ptr_to_node(const ZWay zway, const ZWBYTE *ptr)
{
	return _zway_ptr_to_node_ext(ptr, _zway_get_node_size(zway));
};

static inline void _zway_node_to_ptr_ext(const ZWNODE node, ZWBYTE *ptr, const ZWBYTE size)
{
	_int_to_bytes(node, ptr, size);
};

ZWBYTE _zway_node_to_ptr(const ZWay zway, const ZWNODE node, ZWBYTE *ptr);

ZWBOOL _zway_is_node_valid(const ZWNODE node_id);
ZWNODE _zway_ptr_to_node(ZWay zway, const ZWBYTE *ptr);
ZWBYTE _zway_node_to_ptr(ZWay zway, ZWNODE node, ZWBYTE *ptr);
ZWBOOL _zway_is_subcommand_supported(ZWay zway, const char *path, ZWBYTE sub);
ZWError _zway_check_support(const ZWay zway, const ZWBYTE cmd, const ZWBOOL checkCmd, const ZWBYTE fcId, ZWCSTR path);

ZWBOOL _zway_is_smartstart_supported(const ZWay zway);

static inline void _zway_feed_watchdog_and_yield(const ZWay zway)
{
   return _zthread_feed_watchdog_and_yield(_zway_get_logger(zway));
}

void _zway_device_remove_by_id(const ZWay zway, const ZWNODE node_id);

#endif
